package com.humanminoritygame.web;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.SortedSet;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.humanminoritygame.model.AnswerType;
import com.humanminoritygame.model.CategoryRepo;
import com.humanminoritygame.model.QuestionRepo;
import com.humanminoritygame.model.Room;
import com.humanminoritygame.model.RoomRepo;
import com.humanminoritygame.model.Round;
import com.humanminoritygame.model.Subscription;
import com.humanminoritygame.model.SubscriptionRepo;
import com.humanminoritygame.model.UserRepo;
import com.humanminoritygame.model.UserRoundResult;
import com.humanminoritygame.model.UserRoundResultRepo;

@Controller
public class CsvController {

  SubscriptionRepo subscriptionRepo;
  QuestionRepo questions;
  CategoryRepo categories;
  UserRepo userRepo;
  RoomRepo roomRepo;
  UserRoundResultRepo userRoundResults;
  SessionFactory sessionFactory;

  @Autowired
  public CsvController(SubscriptionRepo subscriptions, QuestionRepo questions,
      CategoryRepo categories, UserRepo users, RoomRepo rooms,
      UserRoundResultRepo userRoundResults, SessionFactory sessionFactory) {
    this.userRepo = users;
    this.subscriptionRepo = subscriptions;
    this.questions = questions;
    this.categories = categories;
    this.roomRepo = rooms;
    this.userRoundResults = userRoundResults;
    this.sessionFactory = sessionFactory;
  }

  @RequestMapping(method = RequestMethod.GET)
  public void getSubscriptionHistory(@RequestParam("id") Long id, HttpServletRequest request,
      HttpServletResponse response) throws Exception {
    response.setContentType("application/octet-stream");
    response.setHeader("Content-Disposition", "attachment;filename=history.csv");
    try {
      ServletOutputStream out = response.getOutputStream();
      StringBuffer sb = generateCsvForSubscription(id);
      InputStream in = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
      byte[] outputByte = new byte[4096];
      // copy binary contect to output stream
      while (in.read(outputByte, 0, 4096) != -1) {
        out.write(outputByte, 0, 4096);
      }
      in.close();
      out.flush();
      out.close();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  
  
  @RequestMapping(method = RequestMethod.GET)
  public void getRoomHistory(@RequestParam("id") Long id, HttpServletRequest request,
      HttpServletResponse response) throws Exception {
    response.setContentType("application/octet-stream");
    response.setHeader("Content-Disposition", "attachment;filename=roomhistory.csv");
    try {
      ServletOutputStream out = response.getOutputStream();
      StringBuffer sb = generateCsvForRoom(id);
      InputStream in = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
      byte[] outputByte = new byte[4096];
      // copy binary contect to output stream
      while (in.read(outputByte, 0, 4096) != -1) {
        out.write(outputByte, 0, 4096);
      }
      in.close();
      out.flush();
      out.close();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  

  private StringBuffer generateCsvForSubscription(Long id) {
    StringBuffer writer = new StringBuffer();
    Subscription s = subscriptionRepo.getSubscription(id);
    if(s==null){
      return invalidCsv();
    }
    int i = 0;
    writer.append("Round, Result, User Vote\n");
    for(UserRoundResult urr : userRoundResults.getOrderedUserRoundResults(s)){
      if(urr.getRound().getSummary() != null){
        writer.append(i++);
        writer.append(",");
        writer.append(booleanAnswer(urr.getRound().getSummary().getAnswer()));
        writer.append(",");
        writer.append(booleanAnswer(urr.getAnswer()));
        writer.append("\n");
      }
    }
    return writer;
  }

  
  private StringBuffer generateCsvForRoom(Long id) {
    StringBuffer writer = new StringBuffer();
    Room room = roomRepo.getRoomById(id);
    if(room==null){
      return invalidCsv();
    }
    SortedSet<Subscription> subscriptions = room.getActiveSubscriptions(); 
    int i = 1;
    writer.append("Round, Result ");
    for(Subscription s: subscriptions){
      writer.append(", ");
      writer.append(s.getUser().getName());
    }
    writer.append("\n");
    SortedSet<Round> rounds = room.getRounds();
    for(Round round: rounds){
      if(round.getSummary()!=null){
        writer.append(i++);
        writer.append(", ");
        writer.append(booleanAnswer(round.getSummary().getAnswer()));
        for(Subscription s: subscriptions){
          UserRoundResult urr = userRoundResults.getUserRoundResult(round, s);
          writer.append(", ");
          if(urr != null){
            writer.append(booleanAnswer(urr.getAnswer()));
          }else{
            writer.append(0);
          }
        }
        writer.append("\n");
      }
    }
    return writer;
  }
  
  private int booleanAnswer(AnswerType answer) {
    if(answer.equals(AnswerType.A)){
      return 1;
    }else if(answer.equals(AnswerType.B)){
      return -1;
    }
    return 0;
  }

  private StringBuffer invalidCsv() {
    StringBuffer writer = new StringBuffer();
    writer.append("bad request");
    return writer;
  }
}
